SWAGOLX.EXE (c) 1993 GDSOFT ALL RIGHTS RESERVED 00010 1 08-24-9413:31ALL JORDAN RITTER SoundBlaster Detect SWAG9408 o¿F 19 ■" {ππPB> It's me again. I need code to detect a SB/SB Compat. card. I haveπPB> code which will detect the port, but I also need a way of detecting theπPB> SB's IRQ and DMA channel. Is there any such code available?ππThis code was just posted about 2 weeks ago (I believe)... }πππProgram DetectSoundBlaster;ππUses DOS, CRT;ππFunction hex(a : Word; b : Byte) : String;πConst digit : Array[$0..$F] Of Char = '0123456789ABCDEF';πVar i : Byte;π xstring : String;πBeginπ xstring:='';π For i:=1 To b Doπ Beginπ Insert(digit[a And $000F], xstring, 1);π a:=a ShR 4π End;π hex:=xstringπEnd; {hex}ππProcedure SoundPort;πVar xbyte1, xbyte2, xbyte3, xbyte4: Byte;π xword, xword1, xword2, temp, sbport: Word;π sbfound, portok: Boolean;ππBeginπ ClrScr;π Write('Sound Blaster: ');π sbfound:=False;π xbyte1:=1;π While (xbyte1 < 7) And (Not sbfound) Doπ Beginπ sbport:=$200 + ($10 * xbyte1);π xword1:=0;π portok:=False;π While (xword1 < $201) And (Not portok) Doπ Beginπ If (Port[sbport + $0C] And $80) = 0 Thenπ portok:=True;π Inc(xword1)π End;π If portok Thenπ Beginπ xbyte3:=Port[sbport + $0C];π Port[sbport + $0C]:=$D3;π For xword2:=1 To $1000 Do {nothing};π xbyte4:=Port[sbport + 6];π Port[sbport + 6]:=1;π xbyte2:=Port[sbport + 6];π xbyte2:=Port[sbport + 6];π xbyte2:=Port[sbport + 6];π xbyte2:=Port[sbport + 6];π Port[sbport + 6]:=0;π xbyte2:=0;π Repeatπ xword1:=0;π portok:=False;π While (xword1 < $201) And (Not portok) Doπ Beginπ If (Port[sbport + $0E] And $80) = $80 Thenπ portok:=True;π Inc(xword1)π End;π If portok Thenπ If Port[sbport + $0A] = $AA Thenπ sbfound:=True;π Inc(xbyte2);π Until (xbyte2 = $10) Or (portok);π If Not portok Thenπ Beginπ Port[sbport + $0C]:=xbyte3;π Port[sbport + 6]:=xbyte4;π End;π End;π If sbfound Thenπ Beginπ Write('Yes');π Write(' Port: ');π Write('$', Hex(sbport, 3));π Endπ Elseπ Inc(xbyte1);π End;π If Not sbfound Thenπ Write('No');πEnd;{soundport}ππBeginπ SoundPort;πEnd.ππ 2 08-24-9413:40ALL JASON DYER Fm-voices SWAG9408 sm 20 ■" {πCould somebody tell me how to program the FM-voices of my sound-blaster ?ππHere's a .sbi player for you...π}πprogram SBIread;πuses Crt;πconst SBIREG : array[1..11] of Word =π ($20,$23,$40,$43,$60,$63,$80,$83,$E0,$E3,$C0);πvarπ FromF: file;π I: integer;π FN: string;π NumRead, NumWritten: Word;π buf: array[1..2048] of Char;π ch: char;π IsSBI: boolean;π SBIName: string;πprocedure Bit;πbeginπ Delay(1); {something fancier was suggested, but this works fine}πend; ππfunction CheckSoundCard: boolean;πvar Temp, Temp2: byte;πbeginπ port[$388]:=$4; repeat until Port[$22E] > 127;π port[$389]:=$60; repeat until Port[$22E] > 127;π port[$389]:=$80; repeat until Port[$22E] > 127;π Temp:=port[$388];π port[$388]:=$2; repeat until Port[$22E] > 127;π port[$389]:=$FF; repeat until Port[$22E] > 127;π port[$388]:=$4; repeat until Port[$22E] > 127;π port[$389]:=$21; repeat until Port[$22E] > 127;π Delay(1);π Temp2:=port[$388];π port[$388]:=$4; repeat until Port[$22E] > 127;π port[$389]:=$60; repeat until Port[$22E] > 127;π port[$389]:=$80; repeat until Port[$22E] > 127;π If ((temp and $E0)=$00) and ((temp2 and $E0)=$c0) thenπ CheckSoundCard:=True else CheckSoundCard:=False;πend;πprocedure ClearCard;πvar CP: byte;πbeginπ For CP:=0 to 255 do beginπ port[$388]:=CP;π port[$389]:=0;π end;πend;πprocedure Sounder(A,B: byte);πbeginπ port[$388]:=A; Bit;π port[$389]:=B; Bit;πend;πbeginπ Writeln('SBI file player');π if not CheckSoundCard then beginπ writeln('Soundcard not detected!');π halt(1);π end;π FN:=ParamStr(1);π If Pos('.',FN)=0 then FN:=FN+'.SBI';π Assign(FromF, FN);π Reset(FromF, 1);π BlockRead(FromF,buf,SizeOf(buf),NumRead);π Close(FromF);π If (buf[1]='S') and (buf[2]='B') and (buf[3]='I') and (ord(buf[4])=26)π then IsSBI:=True else IsSBI:=False;π If IsSBI=False then Writeln('Not a SBI file!') else beginπ SBIName:='';π I:=4;π repeatπ i:=i+1;π if (ord(buf[i])<>0) then SBIName:=SBIName+buf[i];π until ord(buf[i])=0;π Writeln('Name of file : ',FN);π Writeln('Name of instrument: ',SBIName);π ClearCard;π for i:=1 to 11 do Sounder(SBIreg[i],ord(buf[i+36]));π Sounder($A0,$58);π Sounder($B0,$31);π Delay(900);π ClearCard;π end;πend.π 3 08-24-9413:46ALL CHRISTIAN KULLANDER Max Volume on SB SWAG9408 ÷L≈┌ 9 ■" {π KP> HOW CAN I CHANGE THE OVERALL VOLUME OF SOUND BLASTER ? It must be aπ KP> single OUT , or something . . .ππActually I did a small program yesterday that maximizes the master, VOC and FMπvolumes... Here it is:ππ[------------------------------ C u t -----------------------]π}ππprogram MaxVol;ππ beginπ Port[$224] := 4; { register 04h - VOC volume }π Port[$225] := $FF;π Port[$224] := $22; { register 22h - *** Master volume *** }π Port[$225] := $FF;π Port[$224] := $26; { register 26h - FM volume }π Port[$225] := $FF;π end.ππ{ππThis works fine on the SB16 I'm using, and it should work as well with all theπother SB models.πThe left volume is in one of the nibbles, and the right in the other (I can'tπremember which one is in which nibble though...;).πThe max volume for L/R is 15/15, and since 15 shl 4 or 15 = 255 (0FFh) that'sπthe value I use. I haven't tried but I guess that you can use the 225h port toπread the register contents as well as write it.ππ // Christian Kullanderπ}π 4 08-24-9413:49ALL OSCAR WAHLBERG Sound/NoSound (BASM) SWAG9408 ;î╧ 6 ■" πUses CRT;ππ Procedure Sound (Hertz : Word);Assembler;π Asmπ Mov Bx,SPπ Mov Bx,&Hertzπ Mov Ax,34DDhπ Mov Dx,0012hπ CMP Dx,Bxπ JNB @J1π Div Bxπ Mov Bx,Axπ In Al,61hπ Test Al,03hπ JNZ @J2π OR Al,03hπ OUT 61h,Alπ Mov Al,-4Ahπ OUT 43h,Alπ @J2:π Mov Al,Blπ OUT 42h,Alπ Mov Al,Bhπ Out 42h,Alπ @J1:π End; {Sound}ππ Procedure NoSound;Assembler;π Asmπ IN AL,61hπ AND AL,0FChπ OUT 61h,ALπ End;ππBeginππ SOUND (150);π DELAY (100);π SOUND (400);π DELAY (100);π NOSOUND;πEND. 5 08-25-9409:08ALL RODNEY JOHNSON FM Synth Code SWAG9408 b╗∙Y 39 ■" {π I got FM-synth code for the PAS (originally for the SB). Here it is:π}πProgram fmtest;πusesπ sbfm, crt;πconstπ instrument: TFMInstrument = (SoundCharacteristic: ($11, $1);π Level: ($8A, $40);π AttackDecay: ($F0, $F0);π SustainRelease: ($FF, $B3);π WaveSelect: ($01, $00);π FeedBack: $00;π Filler: ($06, $00, $00, $00, $00, $00));π notes: array[0..12] of integer = ($157, $16B, $181, $198, $1B0, $1C1, $1E5,π $202, $220, $241, $263, $287, $2AE);πbeginπ SbFMReset;π SbFMSetVoice(0,@instrument);π SbFMSetVoice(1,@instrument);π SbFMSetVoice(11,@instrument);π SbFMSetVoice(12,@instrument);ππ SbFMKeyOn(0,notes[0],2);π delay(250);π SbFMKeyOn(1,notes[4],3);π delay(250);π SbFMKeyOn(1,notes[7],3);π delay(250);π SbFMKeyOn(1,notes[12],3);π delay(1000);ππ sbFMKeyOff(0);π sbFMKeyOff(1);π sbFMKeyOff(11);π sbFMKeyOff(12);π sbFMReset;πend.ππUnit SbFM;πinterfaceπtypeπ PFMInstrument = ^TFMInstrument;π TFMInstrument = recordπ SoundCharacteristic:array[0..1] of byte;π Level: array[0..1] of byte;π AttackDecay: array[0..1] of byte;π SustainRelease: array[0..1] of byte;π WaveSelect: array[0..1] of byte;π Feedback: byte;π filler: array[0..5] of byte;π end;πconstπ SbIOAddr=$220;π LeftFmAddress=0;π RightFmAddress=2;π FMADDRESS=$08;πProcedure WriteFM(chip, addr, data: byte);πProcedure SbFmReset;πProcedure SbFMKeyOff(voice: integer);πProcedure SbFMKeyOn(voice, freq, octave: integer);πProcedure SbFMVoiceVolume(voice, vol: integer);πprocedure sbFMSetVoice(voicenum: integer; Ins: PFMInstrument);πimplementationπProcedure WriteFM(chip, addr, data: byte);πvarπ ChipAddr: integer;π t: byte;πbeginπ if chip>0 then chipaddr:=SbIOAddr + RightFMAddress elseπ chipaddr:=sbIOAddr + LeftFMAddress;π chipaddr:=SbIOAddr + FMAddress;π asmπ push dxπ push axπ push cxπ mov dx,chipaddrπ mov al,addrπ out dx,alπ in al,dxπ inc dxπ mov al,dataπ out dx,alπ dec dxπ mov cx,4π@L:π in al,dxπ loop @Lπ pop cxπ pop axπ pop dxπ end;πend;πProcedure SbFmReset;πBeginπ WriteFM(0, 1, 0);π WriteFM(1, 1, 0);πend;πProcedure SbFMKeyOff(voice: integer);πvarπ regnum: byte;π chip: integer;πbeginπ chip:=voice div 11;π regnum:=$B0 + (voice mod 11);π WriteFM(chip, regnum, 0);πend;πProcedure SbFMKeyOn(voice, freq, octave: integer);πvarπ regnum, t: byte;π chip: integer;πbeginπ chip:=voice div 11;π regnum:=$A0 + (voice mod 11);π WriteFM(chip, regnum, freq and $FF);π regnum:=$B0 + (voice mod 11);π t:=(freq shr 8) or (octave shl 2) or $20;π WriteFM(chip, regnum, t);πend;πProcedure SbFMVoiceVolume(voice, vol: integer);πvarπ regnum: byte;π chip: integer;πbeginπ chip:=voice div 11;π regnum:=$40 + (voice mod 11);π WriteFM(chip, regnum, vol);πend;πprocedure sbFMSetVoice(voicenum: integer; Ins: PFMInstrument);πvarπ opcellnum: byte;π celloffset, i, chip: integer;πbeginπ chip:=voicenum div 11;π voicenum:=voicenum mod 11;π celloffset:=(voicenum mod 3) + ((voicenum div 3) shr 3);π opcellnum:=$20 + celloffset;π WriteFM(chip, opcellnum, ins^.SoundCharacteristic[0]);π inc(opcellnum, 3);π WriteFM(chip, opcellnum, ins^.SoundCharacteristic[1]);π opcellnum:=$40 + celloffset;π WriteFM(chip, opcellnum, ins^.level[0]);π inc(opcellnum, 3);π WriteFM(chip, opcellnum, ins^.Level[1]);π opcellnum:=$60 + celloffset;π WriteFM(chip, opcellnum, ins^.AttackDecay[0]);π inc(opcellnum, 3);π WriteFM(chip, opcellnum, ins^.AttackDecay[1]);π opcellnum:=$80 + celloffset;π WriteFM(chip, opcellnum, ins^.SustainRelease[0]);π inc(opcellnum, 3);π WriteFM(chip, opcellnum, ins^.SustainRelease[1]);π opcellnum:=$E0 + celloffset;π WriteFM(chip, opcellnum, ins^.WaveSelect[0]);π inc(opcellnum, 3);π WriteFM(chip, opcellnum, ins^.WaveSelect[1]);π opcellnum:=$C0 + voicenum;π WriteFM(chip, opcellnum, ins^.feedback);πend;πend.ππ{πMessage 1 is FMTEST.PASπMessages 2+3 are SBFM.PASπThat's all. One thing: if you can make this work with more than twoπvoices at a time, I'd be interested in improved code. I think that thisπcode uses the AdLib compatibility, which is by no means impressive :-).π}π 6 08-25-9409:11ALL JURI PAKASTE S3M header SWAG9408 J8«~ 47 ■" {πFrom: jurip@clinet.fi (Juri Pakaste)ππHopefully someone here has experience reading S3M headers...πI'm trying to read the S3M header. I get the name right, I thinkπI get the number of instruments right, but I can't get the numberπof patterns right. If I understand correctly the file which comesπwith Scream Tracker 3.01 (see below), the number of patternsπshould be located in bytes 35-36 (why on earth two bytes? Whoπwould use over 255 patterns?). The numbers I get have nothing toπdo with numbers DMP and Inertia Player give, though. My little test-πprogram, S3MREAD.EXE, tells me, for example, that a module that hasπ55 (I think) patterns, has in fact 99. Just great. Some of the valuesπit gives manage to get pretty near the ones DMP and IPlay give,πbut... you get the idea.ππHere is there relevant part of S3M technical documentation:ππ------------------------------------8<----------------------------------π π Song/Module headerπ 0 1 2 3 4 5 6 7 8 9 A B C D E Fπ -----------------------------------------------------------------π 0000: | Song name, max 28 chars (incl. NUL) |π |---------------------------------------------------------------|π 0010: | |1Ah|Typ| x | x |π |---------------------------------------------------------------|π 0020: |OrdNum |InsNum |PatNum | Flags | Cwt/v | Ffv |'S'|'C'|'R'|'M'|π |---------------------------------------------------------------|π 0030: |m.v|i.s|i.t|m.m| x | x | x | x | x | x | x | x | x | x | x | x |π |---------------------------------------------------------------|π 0040: |Channel settings for 32 channels, 255=unused,+128=disabled |π |---------------------------------------------------------------|π 0050: | |π |---------------------------------------------------------------|π 0060: |Orders; length=OrdNum (must be even) |π |---------------------------------------------------------------|π xxxx: |Parapointers to instruments; length=InsNum*2 |π |---------------------------------------------------------------|π xxxx: |Parapointers to patterns; length=PatNum*2 |π -----------------------------------------------------------------ππ π Typ = File type: 16=module,17=songπ Ordnum = Number of orders in fileπ Insnum = Number of instruments in fileπ Patnum = Number of patterns in fileπ Cwt/v = Created with tracker / version: &0xfff=version, >>12=trackerπ ST30:0x1300π Ffv = File format version;π 1=originalπ 2=original BUT samples unsignedπ Parapointers are OFFSET/16 relative to the beginning of the header.π π PLAYING AFFECTORS / INITIALIZERS:π Flags = +1:st2vibrato π +2:st2tempoπ +4:amigaslidesπ +8:0vol optimizationsπ +16:amiga limitsπ +32:enable filter/sfxπ m.v = master volumeπ m.m = master multiplier (&15) + stereo(=+16)π i.s = initial speed (command A)π i.t = initial tempo (command T)π π Channel types:π &128=on, &127=type: (127=unused)π 8 - L-Adlib-Melody 1 (A1) 0 - L-Sample 1 (S1)π 9 - L-Adlib-Melody 2 (A2) 1 - L-Sample 2 (S2)π 10 - L-Adlib-Melody 3 (A3) 2 - L-Sample 3 (S3)π 11 - L-Adlib-Melody 4 (A4) 3 - L-Sample 4 (S4)π 12 - L-Adlib-Melody 5 (A5) 4 - R-Sample 5 (S5)π 13 - L-Adlib-Melody 6 (A6) 5 - R-Sample 6 (S6)π 14 - L-Adlib-Melody 7 (A7) 6 - R-Sample 7 (S7)π 15 - L-Adlib-Melody 8 (A8) 7 - R-Sample 8 (S8)π 16 - L-Adlib-Melody 9 (A9)π 26 - L-Adlib-Bassdrum (AB)π 17 - R-Adlib-Melody 1 (B1) 27 - L-Adlib-Snare (AS)π 18 - R-Adlib-Melody 2 (B2) 28 - L-Adlib-Tom (AT)π 19 - R-Adlib-Melody 3 (B3) 29 - L-Adlib-Cymbal (AC)π 20 - R-Adlib-Melody 4 (B4) 30 - L-Adlib-Hihat (AH)π 21 - R-Adlib-Melody 5 (B5) 31 - R-Adlib-Bassdrum (BB)π 22 - R-Adlib-Melody 6 (B6) 32 - R-Adlib-Snare (BS)π 23 - R-Adlib-Melody 7 (B7) 33 - R-Adlib-Tom (BT)π 24 - R-Adlib-Melody 8 (B8) 34 - R-Adlib-Cymbal (BC)π 25 - R-Adlib-Melody 9 (B9) 35 - R-Adlib-Hihat (BH)ππSo, shouldn't this piece of code be able to read the name,πnumber of instruments and number of patterns right:ππ}πProgram S3MReader;πVarπ NameArray : Array [1..28] Of Char;π InstrArray, PatArray : Array [1..2] Of Byte;π InstrByte, PatByte : Byte;π f : File;π i : Integer;π j : Integer;π S3MName : String;ππBeginπ WriteLn;π WriteLn;π If ParamCount = 1 Thenπ Beginπ Assign(f,ParamStr(1));π Reset(f,1);π BlockRead(f,NameArray,28,i);π For j := 1 To 28 Do S3MName := S3MName + NameArray[j];π j := 28;π While (Ord(S3MName[Length(S3MName)]) = 0) Or (Ord(S3MNameπ (continues...)[Length(S3MName)]) = 32) Doπ Beginπ j := j - 1;π S3MName[0] := Chr(j);π End;π Seek(f,33);π BlockRead(f,InstrArray,2,i);π InstrByte := InstrArray[1] + InstrArray[2];π BlockRead(f,PatArray,2,i);π PatByte := PatArray[1] + PatArray[2];π WriteLn('Name: ',S3MName);π WriteLn('Number of instruments: ',InstrByte);π WriteLn('Number of patterns: ',PatByte);π Close(f);π End;πEnd.ππ 7 08-25-9409:11ALL ADRIAN DENOON PROGRAMMING SB AND FM SWAG9408 └┴ë 43 ■" {πAs I promised, here is the other reply that I am sending you containing theπinformation on Programming the SB via CT-VOICE.DRV.ππBefore I begin, This message may be a little long, so if for any reason, youπloose the end of it or sumthin', let me know, and I'll repost it split upπinto sections, but right now I'll just make one long message.ππO.K. Here we go...πThe information supplied will concern playback and recording of digitalπsamples on the SB's digital channel(s) using the driver supplied byπCreative Labs, CT-VOICE.DRV.ππThere should be a lot of information available on BBS's if you look for itπand want to follow up anything, but for the meaan time, this informationπis taken from a book called "The Sound Blaster Book" by Axel Stolz,πpublished by Abacus ISBN 1-55755-164-2.ππLet me first correct myself about the comment that the driver is executedπas an interrupt... Similar, but not quite... You don't actually make andπinterrupt call (i.e: INT n), but rather make the actual call to the addressπthat the driver was loaded into (i.e: CALL n).ππThe first thing you need to do is load the driver into memory. Note, theπsegment may be anywhere (you store the pointer as a reference), but theπoffset MUST be zero. The loading is done as follows...π1.) Allocate memory and get pointer to the block.π2.) Load the driver from disk into the allocated space.πNote: I am not going into much detail regarding error checking, but youπshould do checking on things such as allocation being ok and not NULL, andπsee whether the file exists on the disk, and whether or not it is a validπdriver (this can be done by checking to see that the letters "CT" areπcontained in bytes 3 and 4).ππThe code is as follows (in Pascal):π(Please forgive any minor discrepencies, as I am not a Pascal programmer,π but a C programmer, and I'm only trying to extract those sections that seemπ inportant, so I may not know which functions are Pascal's and which areπ user defined, but you should get the general idea. )π}πVARπ F : File;π PtrToDrv : Pointer;ππBEGINπ Assign( F, 'CT-VOICE.DRV' );π Reset( F, 1 );π AllocateMem( PtrToDrv, FileSize(F) );π Blockread( F, PtrToDrv^, FileSize(F) );π Close( F );πEND;π{πNOTE: The varible PtrToDrv should be global, as you will be needing it toπreference the memory at a later stage.ππNow that you have the driver loaded, you can start to make function callsπto it. This is done by setting the register BX to the number of theπfunction that you want to execute, and various other memory registers toπthe parameters, and then calling the address stored in the "PtrToDrv"πvarible. Return values are usually stored in the register AX.ππEXAMPLE: Function 6: Play a sample:π-------- Input registers: BX = Function numberπ ES:DI = Pointer to sampleπ Return registers: None.π}πPROCEDURE PlaySample( BufferAddr : Pointer );πVARπ VSeg, VOfs : WORD;πBEGINπ VSeg := Seg( BufferAddr^ );π VOfs := Ofs( BufferAddr^ );π ASMπ MOV BX, 6π MOV ES, VSegπ MOV Di, VOfsπ CALL PtrToDrvπ END;πEND;ππ{πThe following are a list of all the function available from the CT-VOICE.DRVπdriver. Note, you will call them by setting BX = function number, settingπthe other registers, and then executing "CALL PtrToDrv":ππ----------------------------------------------------------------------------π#: Description: Parameters:π-- ------------------------- -------------------------------------------π0 Determain driver version AH=Main number (on return)π AL=Sub number (on return)ππ1 Set port address AX=Port addressππ2 Set interrupt AX=Interrupt numberππ3 Initialize driver AX=0 Successfull (on return)π AX=1 SB not found (on return)π AX=2 Port address error (on return)π AX=3 Interrupt error (on return)ππ4 Loudspeaker on/off AL=0 offπ AL=1 onππ5 Set "StatusWord" address ES:DI=Status addressπ (The WORD varible at this address will storeπ the status of the playback so that you canπ monitor the playback of the sample.)ππ6 Sample playback ES:DI=Sample addressππ7 Record sample AX=Sampling rateπ DX:CX=Lengthπ ES:DI=Sample addressππ8 Abort sample noneππ9 De-Install driver noneπ π10 Pause Sample AX=0 Successfull (on return)π AX=1 Not successfull (on return)ππ11 Continue sample AX=0 Successfull (on return)π AX=1 Not successfull (on return)ππ12 Interrupt loop AX=0 At end of loopπ AX=1 Immediatelyπ AX=0 Successfull (on return)π AX=1 No loop being executedππ13 User defined driver function DX:AX=Function addressπ ES:BX=Address of the current data blockπ}π 8 08-25-9409:11ALL GREG VIGNEAULT SoundBlaster version... SWAG9408 ∙│ï 17 ■" {π Someone in an Assembly conference posted a routine to determine theπ version of a Sound Blaster card. I've adapted it for use in TP ...π}ππPROGRAM sb; { Determine Sound Blaster version. TP5+ }π { Jul.13.94 Greg Vigneault }πUSES Dos, { import GetEnv }π Crt; { import Delay }πVAR Major, Minor : BYTE; { version has major & minor parts }ππ(*-----------------------------------------------------------------*)π{ this procedure returns 0.0 if any error condition... }πPROCEDURE SBver (VAR Maj, Min : BYTE);π VAR bev : STRING[32]; { environment string }π j,k : WORD; { scratch variables }π BEGINπ Maj := 0; Min := 0; { initialize }π bev := GetEnv('BLASTER'); { look in environment }π IF bev[0] = #0 THEN EXIT; { no sign of Blaster }π j := Pos('A',bev); { search for i/o port }π IF j = 0 THEN EXIT ELSE INC(j); { none? }π Val( '$'+Copy(bev,j,3), j, k ); { base port number }π IF k <> 0 THEN EXIT; { if bad port value }π INC(j,$C); { command port }π Port[j] := $E1; { command }π DEC(j,2); { input port }π Delay(20); { wait for response }π Maj := Port[j]; { version major part }π Delay(20); { wait for response }π Min := Port[j]; { version minor part }π END {SBver};ππBEGINππ SBver (Major, Minor);π WriteLn;π WriteLn ('Sound Blaster version: ',Major,'.',Minor);π WriteLn;ππEND.π 9 08-25-9409:12ALL DANIEL SANDS Wav Player SWAG9408 ½mPδ 62 ■" {π>Does anybody know how to load and play a wav in pascal? And I still need toπ>know how to load mods. And I would like to know how to load any other soundπ>files that you know of other than pc speaker beeps. ThanksππI made a WAV player in Pascal, but the source is a few lines long. <G>ππ Okay. It will play 4-bit ADPCM wavs, but not well. Need to get the SBπdeveloper's kit to figure out why. Oh well.π}ππ{$M 16384,0,655360}ππuses Dos, CRT, objects;ππconst SBase = $220; {Default port base for Sound Blaster.π Change if necessary}π SIrq = 7; {Default Irq line for Sound Blaster.π Change if necessary}π SDMA = 1; {Default DMA channel for Sound Blaster.}ππtypeπ TWAVRec = recordπ ID: LongInt;π Len: LongInt;π end;π PWAVFmt = ^TWAVFmt;π TWAVFmt = recordπ case word ofπ 1:( FTag: word;π NChan: word;π SampR: word;π AvgSR: word;π BLKAl: word;π FMTLen: word;π FMTDat: array[0..256] of byte);π 2:( Chunk:Pointer);π end;πvarπ WAVFile: TDosStream; {WAV file object}π BlkID: TWAVRec; {ID for each block in WAV}π BlkFmt: PWAVFmt; {Block format}π TotalSz: LongInt; {Total size of WAV data}π DSPCmd: byte;π NumBits: byte;π SampByte: byte;π BlockSize: word;π EOB: boolean;π DF: String;ππprocedure NewBlock; interrupt; {Procedure to set up next block or}πvar X:Byte; {end playback}πbeginππ X := port[SBase+$e];π port[$20] := $20;π EOB := true;ππend;ππprocedure PrepareSB;πbeginππ SetIntVec(SIrq + 8, @NewBlock); {Set up service routine}ππ asmπ in al,$61 {Enable timer 2, but}π and al,$fc {do not turn on sound.}π or al,1π out $61,alππ stiππ mov dx,SBase+6 {DSP (Digital Sound Processor)π reset port}π mov al,1 {Reset command}π out dx,alππ mov bx,4π call @9 {Wait 4 clocks}ππ mov al,0 {Normal mode}π out dx,alππ @3: mov dx,SBase+$e {DSP status port}π @2: in al,dx {Read status}π test al,$80 {If high bit not set, no data}π jz @2 {ready}ππ mov dx,Sbase+$a {DSP read port}π in al,dx {Read status}π cmp al,$aa {AA indicates ready}π jnz @3π jmp @4π @5:π in al,dx {Wait for response to last byte}π test al,$80 {sent}π jnz @5π mov al,ahπ out dx,al {Send next byte}π retππ @9:π push bxπ mov al,$b6 {Write count to timer #3}π out $43,alππ mov al,0 {Low byte of count}π out $42,alππ mov al,$10 {High byte count}π out $42,alππ sub bx,$1000π neg bx {1000h-clocks=desired count}π @10:π mov al,$80 {Read count from timer}π out $43,alππ in al,$42 {Low byte}π mov ah,alπ in al,$42 {High byte}π xchg ah,alππ cmp bx,ax {Pause until count reached}π jl @10π pop bxπ retπ @4:π mov dx,SBase+$cππ mov ah,$40 {Set time constant}π call @5ππ mov ah,SampByte {Time divisor}π call @5ππ end;ππ port[$21] := port[$21] and not (1 shl SIRQ); {Enable SB interrupt}ππend;ππprocedure ErrorEnd;πbeginπ WAVFile.Done;π Writeln('Error in .WAV');π Halt(1);πend;ππprocedure PlaySound(SndLen: longint);ππvar AbsAddr: LongInt;π FirstBlk, SecBlk, CurBlk: Pointer;ππbeginππ EOB := False;ππ GetMem(BlkFmt, BlockSize*2);π FirstBlk := BlkFmt;π SecBlk := pointer(longint(FirstBlk) + BlockSize);π CurBlk := FirstBlk;πππ WAVFile.Read(BlkFmt^, BlockSize);π SndLen := SndLen - BlockSize;ππ repeatπ AbsAddr := Seg(CurBlk^);π AbsAddr := AbsAddr * 16 +Ofs(CurBlk^);π SndLen := SndLen - BlockSize;π asmπ jmp @4ππ @5:π in al,dx {Wait for response to last byte}π test al,$80 {sent}π jnz @5π mov al,ahπ out dx,al {Send next byte}π retππ @4:ππ mov bx,1π mov cx,integer(AbsAddr)π mov dx,SBase+$cππ mov al,0 {Clear byte high/low flip-flop}π out $c,alππ mov al,$49 {Set memory read, single transfer,}π out $b,al {channel 1}ππ mov al,cl {Enter base address}π out SDMA*2,alπ mov al,chπ out SDMA*2,alππ mov ax,integer(AbsAddr+2) {High 4 bits goes to DMA page reg}π mov dx,$83π mov cl,SDMAπ sub cl,2π mov ch,2 {Calculate DMA page address}π shr ch,cl {87, 83, 81, 82 channel order}π xor dl,chπ out dx,al {Send page byte}ππ mov ax,BlockSize {Set byte count}π out SDMA*2+1,alπ xchg al,ahπ out SDMA*2+1,alπ push axππ mov al,SDMA {Re-enable DMA channel 1}π out $a,alππ mov dx,SBase+$c {DSP port}ππ mov ah,DSPCmd {DMA 8-bit transfer}π call @5ππ pop ax {Get transfer again}π mov bl,alπ call @5π mov ah,blπ call @5ππ end;ππ DSPCmd := DSPCmd and $fe;ππ if (CurBlk = FirstBlk) then CurBlk := SecBlk else CurBlk := FirstBlk;π if SndLen > 0 then WAVFile.Read(CurBlk^, BlockSize);ππ while not EOB doπ if Keypressed then ErrorEnd;π EOB := False;ππ until (SndLen<=0);πend;πππbeginππ DF := ParamStr(1);ππ WAVFile.Init(DF, stOpenRead); {Open WAV file}π WAVFile.Read(BlkID, SizeOf(TWAVRec)); {Read in first block}ππ if BlkID.ID = $46464952 then {ID of WAV file}π beginπ TotalSz := BlkID.Len; {Get total size}π repeatπ WAVFile.Read(BlkID, 4); {Read in type chunk}π TotalSz := TotalSz - 4; {and update TS}ππ if BlkID.ID <> $45564157 then ErrorEnd; {Must be "WAVE"}π repeatπ WAVFile.Read(BlkID, SizeOf(TWAVRec)); {Read in format chunk}π TotalSz := TotalSz - SizeOf(TWavRec);ππ if BlkID.ID = $20746d66 then {"fmt ", set WAV format}π beginπ getmem(BlkFmt, BlkID.Len);π WAVFile.Read(BlkFmt^, BlkID.Len);π TotalSz := TotalSz - BlkID.Len;π with BlkFmt^ doπ beginπ if FTag = $200 then DSPCmd := $75 else {ADPCM 4-bit compression}π if FTag = 1 then DSPCmd := $14 else {Normal}π ErrorEnd;π if DSPCmd = $75 then NumBits := 4 else NumBits := 8;π if NChan = 2 then DSPCmd := DSPCmd + 8; {Stereo}π SampByte := 256-(1000000 div SampR); {Sampling rate}π BlockSize := BlkAl; {Size of buffer}π end;π freemem(BlkFmt, BlkID.Len);π end elseππ if BlkID.ID = $61746164 thenπ beginπ PrepareSB; {Perform init stuff}π TotalSz := TotalSz - BlkID.Len;π PlaySound(BlkID.Len);π end elseππ ErrorEnd;π until TotalSz <= 0;π until TotalSz <= 0;π end elseπ ErrorEnd;π WAVFile.Done;π port[$21] := port[$21] or (1 shl SIrq);πend.π 10 08-26-9408:32ALL SWAG SUPPORT TEAM Call AD-LIB sound driver SWAG9408 8#φv 76 ■" unit MusicIO;π{Contains procedures and function to call to Ad-Lib sound Driver.π if Sound Driver is not Loaded the system WILL Crash.π Parameters must be passed backwards since the sound driver is madeπ for a C parameter passing sequence.}ππinterfaceππ usesπ DOS;ππ typeπ Instrument = array[1..26] of integer;ππ varπ GActVoice :word; {Active Voice}π GT :array[0..10] of Instrument; {use global variable to keep array valid}ππ procedure InitDriver;π procedure RelTimeStart(TimeNum,TimeDen :integer);π procedure SetState(State :integer);π function GetState :boolean;π procedure SetMode(PercussionMode :integer);π function SetVolume(VolNum,VolDen,TimeNum,TimeDen :integer) :boolean;π function SetTempo(Tempo,TimeNum,TimeDen :integer) :boolean;π procedure SetActVoice(Voice :word);π function PlayNote(Pitch :integer; LengthNum,LengthDen :word) :boolean;π function SetTimbre(TimeNum,TimeDen :word) :boolean;π procedure SetTickBeat(TickBeat :integer);π procedure DirectNoteOn(Voice :word; Pitch :integer);π procedure DirectNoteOff(Voice :word);π procedure DirectTimbre;π procedure LoadInstrument(FileSpec :string);π function LoadSong(FileSpec :string) :boolean;πππimplementationππ {Returns True if file exists; otherwise, it returns False. Closes the file if it exists.}π function Exist(fs :string) :boolean;π varπ f: file;π beginπ {$I-}π Assign(f,fs);π Reset(f);π Close(f);π {$I+}π Exist:=(IOResult=0) and (fs<>'');π end;πππ procedure InitDriver;π {Initialize Sound Driver}π Varπ r :registers; TmpP:Pointer;π Beginπ GetIntVec(101,TmpP);π If TmpP = Nil Thenπ Beginπ WriteLn('Sound Driver Not Installed!');π Halt(0);π End;ππ R.SI:=0;π Intr(101,r);π End;ππ procedure RelTimeStart(TimeNum,TimeDen :integer);π {Set Relative Time to Start}π varπ TD,TN :integer;π r :registers;π beginπ TD:=TimeDen;π TN:=TimeNum;ππ r.SI:=2;π r.ES:=Seg(TN);π r.BX:=Ofs(TN);ππ Intr(101,r);π end;ππ procedure SetState(State :integer);π {Start or Stop a Song}π varπ r :registers;π beginπ r.SI:=3;π r.ES:=Seg(State);π r.BX:=Ofs(State);ππ Intr(101,r);π end;ππ function GetState :boolean;π varπ r :registers;π beginπ r.SI:=4;π r.ES:=Seg(GetState);π r.BX:=Ofs(GetState);ππ Intr(101,r);ππ GetState:=(r.BP=1);π end;ππ procedure SetMode(PercussionMode :integer);π {Percussion or Melodic Mode}π varπ r :registers;π beginπ r.SI:=6;π r.ES:=Seg(PercussionMode);π r.BX:=Ofs(PercussionMode);ππ Intr(101,r);π end;ππ function SetVolume(VolNum,VolDen,TimeNum,TimeDen :integer) :boolean;π varπ TD,TN,VD,VN :word; {To put variables values in proper order in memory}π r :registers;π beginπ TD:=TimeDen;π TN:=TimeNum;π VD:=VolDen;π VN:=VolNum;ππ r.SI:=8;π r.ES:=Seg(VN);π r.BX:=Ofs(VN);ππ Intr(101,r);ππ SetVolume:=(r.BP=1);π end;ππ function SetTempo(Tempo,TimeNum,TimeDen :integer) :boolean;π varπ TD,TN,TP :integer; {To put variables values in proper order in memory}π r :registers;π beginπ TD:=TimeDen;π TN:=TimeNum;π TP:=Tempo;ππ r.SI:=9;π r.ES:=Seg(TP);π r.BX:=Ofs(TP);ππ Intr(101,r);ππ SetTempo:=(r.BP=1);π end;ππ procedure SetActVoice(Voice :word);π varπ r :registers;π beginπ GActVoice:=Voice;ππ r.SI:=12;π r.ES:=Seg(Voice);π r.BX:=Ofs(Voice);ππ Intr(101,r);π end;ππ function PlayNoteDel(Pitch :integer; LengthNum,LengthDen,DelayNum,DelayDen :word) :boolean;π varπ DD,DN,LD,LN :word;π P :integer;π r :registers;π beginπ P:=Pitch;π LD:=LengthDen;π LN:=LengthNum;π DN:=DelayNum;π DD:=DelayDen;ππ r.SI:=14;π r.ES:=Seg(P);π r.BX:=Ofs(P);ππ Intr(101,r);ππ PlayNoteDel:=(r.BP=1);π end;ππ function PlayNote(Pitch :integer; LengthNum,LengthDen :word) :boolean;π varπ LD,LN :word;π P :integer;π r :registers;π beginπ P:=Pitch;π LD:=LengthDen;π LN:=LengthNum;ππ r.SI:=15;π r.ES:=Seg(P);π r.BX:=Ofs(P);ππ Intr(101,r);ππ PlayNote:=(r.BP=1);π end;ππ function SetTimbre(TimeNum,TimeDen :word) :boolean;π varπ TD,TN :word;π T :^integer;π c1,c2 :byte;π r :registers;π beginπ T:=Addr(GT[GActVoice]);π TN:=TimeNum;π TD:=TimeDen;ππ r.SI:=16;π r.ES:=Seg(T);π r.BX:=Ofs(T);ππ Intr(101,r);ππ SetTimbre:=(r.BP=1);π end;ππ function SetPitch(DeltaOctave,DeltaNum,DeltaDen :integer; TimeNum,TimeDen :word) :boolean;π varπ TD,TN :word;π DD,DN,D :integer;π c1,c2 :byte;π r :registers;π beginπ D:=DeltaOctave;π DN:=DeltaNum;π DD:=DeltaDen;π TN:=TimeNum;π TD:=TimeDen;ππ r.SI:=16;π r.ES:=Seg(D);π r.BX:=Ofs(D);ππ Intr(101,r);ππ SetPitch:=(r.BP=1);π end;ππ procedure SetTickBeat(TickBeat :integer);π varπ r :registers;π beginπ r.SI:=18;π r.ES:=Seg(TickBeat);π r.BX:=Ofs(TickBeat);ππ Intr(101,r);π end;ππ procedure DirectNoteOn(Voice :word; Pitch :integer);π varπ P :integer;π V :word;π r :registers;π beginπ P:=Pitch;π V:=Voice;ππ r.SI:=19;π r.ES:=Seg(V);π r.BX:=Ofs(V);ππ Intr(101,r);π end;ππ procedure DirectNoteOff(Voice :word);π varπ r :registers;π beginπ r.SI:=20;π r.ES:=Seg(Voice);π r.BX:=Ofs(Voice);ππ Intr(101,r);π end;ππ procedure DirectTimbre;π varπ T :^integer;π V :word;π r :registers;π beginπ V:=GActVoice;π T:=Addr(GT[V]);ππ r.SI:=21;π r.ES:=Seg(V);π r.BX:=Ofs(V);ππ Intr(101,r);π end;ππ procedure LoadInstrument(FileSpec :string);π {Load an Instument from Disk and Place in Array}π varπ c1 :byte;π n :integer;π f :file of integer;π beginπ if not(Exist(FileSpec)) then FileSpec:='C:\MUSIC\PIANO1.INS';π Assign(f,FileSpec);π Reset(f);π Read(f,n);π for c1:=1 to 26 doπ Read(f,GT[GActVoice,c1]);π Close(f);π end;ππ function LoadSong;π {Read a .ROL file and place song in Buffer}π varπ nb :byte;π ns :string[255];π ni,ni2,ni3,ni4,BPM :integer;π c1,c2 :word;π nr,nr2 :real;π fl :boolean;π f :file;π procedure StringRead(len :word); {uses f,ns}π varπ nc :char;π c1 :word;π beginπ ns:='';π for c1:=1 to len doπ beginπ BlockRead(f,nc,1);π ns:=ConCat(ns,nc);π end;π end;π procedure TempoRead; {uses f,nb}π varπ b1,b2,b3,b4 :byte;π beginπ BlockRead(f,b1,1);π BlockRead(f,b2,1);π BlockRead(f,b3,1);π BlockRead(f,b4,1);π nb:=(b3{ div 2});π end;π procedure VolumeRead;π varπ b1,b2,b3,b4 :byte;π beginπ BlockRead(f,b1,1);π BlockRead(f,b2,1);π BlockRead(f,b3,1);π BlockRead(f,b4,1);π nb:=51+Round(b3/2.5);π end;π beginπ LoadSong:=true;π if not(Exist(FileSpec))π then beginπ LoadSong:=false;π Exit;π end;ππ InitDriver;π RelTimeStart(0,1);π Assign(f,FileSpec);π Reset(f,1);π StringRead(44);π BlockRead(f,ni,2); SetTickBeat(ni); {Ticks per Beat}π BlockRead(f,ni,2); BPM:=ni; {Beats per Measure}π StringRead(5);π BlockRead(f,nb,1); SetMode(1); {Mode}π StringRead(143);π TempoRead; fl:=SetTempo(nb,0,1); {Tempo}π BlockRead(f,ni,2);π for c1:=1 to ni doπ beginπ BlockRead(f,ni2,2);π TempoRead; fl:=SetTempo(nb,ni2,1); {Tempo}π end;π for c1:=0 to 10 do {11 Voices}π beginπ SetActVoice(c1);π StringRead(15);π BlockRead(f,ni2,2); {Time in ticks of last Note}π c2:=0;π while (c2<ni2) doπ beginπ BlockRead(f,ni3,2); {Note Pitch}π BlockRead(f,ni4,2); {Note Duration}π fl:=PlayNote(ni3-60,ni4,BPM); {Note}π c2:=c2+ni4; {Summation of Durations}π end;π StringRead(15);π BlockRead(f,ni2,2);π for c2:=1 to ni2 do {Instuments}π beginπ BlockRead(f,ni3,2);π StringRead(9);π nb:=Pos(#0,ns);π Delete(ns,nb,Length(ns));π LoadInstrument(ConCat('C:\MUSIC\',ns,'.INS'));π fl:=SetTimbre(ni3,1);π StringRead(1);π BlockRead(f,ni4,2);π end;π StringRead(15);π BlockRead(f,ni2,2);π nb:=1;π for c2:=1 to ni2 do {Volume}π beginπ BlockRead(f,ni3,2);π fl:=SetVolume(100,nb,ni3,1); {Use inverse to disable Relative}π VolumeRead;π fl:=SetVolume(nb,100,ni3,1);π end;π StringRead(15);π BlockRead(f,ni2,2);π for c2:=1 to ni2 do {Pitch -disabled}π beginπ BlockRead(f,ni3,2);π BlockRead(f,nr,4);π if (nr=0) then nr2:=1 else nr2:=nr;π{ fl:=SetPitch(0,Abs(Trunc(nr*100)),Trunc((nr/nr2)*100),ni3,1);}π end;π end;π Close(f);π end;ππend.π